<template>
  <el-dialog append-to-body
             :before-close="beforeClose"
             class="ju-dialog"
             :class="[isStyleReady ? 'visible' : 'invisible',isFullScreen ? 'fullscreen' : '',isMoving || isResizing ? 'moving' : '',isMiniSize ? 'minisize' : '']"
             :close-on-click-modal="false"
             destroy-on-close
             lock-scroll
             :show-close="false"
             top="0"
             :visible.sync="show"
             :width="width"
             @closed="onDialogClosed"
             @mousedown.native.stop="onDialogWrapMouseDown"
             @mousemove.native="onDialogWrapMouseMove"
             @opened="onDialogOpen">
    <template #title>
      <div class="flex-1 p-3"
           @dblclick="doToggleFullScreen">
        {{ title }}
      </div>
      <div class="toolbar d-flex align-items-center pe-1">
        <!-- <el-tooltip content="最小化"
                    :enterable="false"
                    :open-delay="500">
          <ju-icon class="mx-2"
                   icon="dash-lg"
                   svg-icon
                   @click.native.stop="doMiniSize" />
        </el-tooltip> -->
        <el-tooltip :content="isFullScreen ? '还原' : '全屏'"
                    :enterable="false"
                    :open-delay="500">
          <ju-icon class="mx-2"
                   :icon="isFullScreen ? 'arrows-angle-contract' : 'arrows-angle-expand'"
                   svg-icon
                   @click.native.stop="doToggleFullScreen" />
        </el-tooltip>
        <el-tooltip content="关闭"
                    :enterable="false"
                    :open-delay="500">
          <ju-icon class="ju-icon-close mx-2"
                   icon="x-lg"
                   svg-icon
                   @click.native.stop="doClose" />
        </el-tooltip>
      </div>
    </template>
    <iframe class="w-100 h-100 p-0 border-0"
            sandbox="allow-scripts allow-forms allow-same-origin"
            seamless="seamless"
            :src="url"></iframe>
    <div class="move-mask position-absolute"
         :class="isMoving || isResizing ? 'visible ' : 'invisible'"></div>
  </el-dialog>
</template>

<script lang="ts">
  import { Component, Vue, Watch } from "@some21/vue-class-decorator";

  // 窗体的最小大小范围
  const minWidth = 300;
  const minHeight = 200;

  @Component({
    name: "JuDialog",
  })
  export default class extends Vue {
    show = false;
    width = "500px";
    height = "400px";
    url = "about:blank";
    title = "";

    isMoving = false; // 控制是否处于拖动中
    isStyleReady = false; // 控制样式是否初始化完毕
    isFullScreen = false; // 是否全屏
    isMiniSize = false; // 是否最小化
    isResizing = false; // 是否正在调整大小
    resizeType = 0; // 0001：left ，0010 ：right ,0100:top ,1000:bottom

    get elDialogBody() {
      return this.$el.querySelector<HTMLDivElement>("[class^=el-dialog__body]");
    }
    get elDialog() {
      return this.$el.querySelector<HTMLDivElement>("[class^=el-dialog]");
    }
    get elDialogHeader() {
      return this.$el.querySelector<HTMLDivElement>("[class^=el-dialog__header]");
    }
    get elDialogWrap() {
      return this.$el as HTMLDivElement;
    }
    @Watch("width")
    onWidthChange() {
      this.elDialog.style.width = this.width;
    }
    @Watch("height")
    onHeightChange() {
      this.elDialog.style.height = this.height;
    }

    doToggleFullScreen() {
      this.isFullScreen = !this.isFullScreen;
    }
    doClose() {
      this.show = false;
      this.$destroy();
    }
    doMiniSize() {
      this.isMiniSize = true;
      this.show = false;
    }

    mounted() {
      this.elDialog.style.cssText += `;margin:0;height:${this.height}`; // 默认位置
      this.elDialog.classList.add("d-flex", "flex-column", "position-absolute", "m-0", "user-select-none");
      this.elDialogHeader.classList.add("d-flex", "p-0");
      this.show = true;
    }

    onDialogWrapMouseDown(e) {
      if (!this.isFullScreen && !this.isMoving && this.resizeType) {
        this.isResizing = true;
        const elDialogRect = this.elDialog.getBoundingClientRect();
        // 鼠标按下，计算当前元素距离可视区的距离
        const startX = e.clientX;
        const startY = e.clientY;
        const startDialogOffsetLeft = this.elDialog.offsetLeft;
        const startDialogOffsetTop = this.elDialog.offsetTop;
        const startDialogWidth = this.elDialog.offsetWidth;
        const startDialogHeight = this.elDialog.offsetHeight;

        const maxWidth = document.body.clientWidth - startDialogOffsetLeft; // 可用的最大宽度
        const maxHeight = document.body.clientHeight - startDialogOffsetTop; // 可用的最大高度

        const onMouseMove = e => {
          // 通过事件委托，计算移动的距离
          if ((this.resizeType & (1 << 0)) === 1 << 0) {
            // 在左侧
            let left = e.clientX - startX + startDialogOffsetLeft;
            // 边缘处理
            if (left < 0) {
              left = 0;
            }
            // 最小宽度处理
            let width = elDialogRect.right - left;
            if (width < minWidth) {
              width = minWidth;
              left = elDialogRect.right - width;
            }
            // this.elDialog.style.cssText += `;left:${left}px;width:${width}px`;
            this.elDialog.style.cssText += `;left:${left}px`;
            this.width = `${width}px`;
          } else if ((this.resizeType & (1 << 1)) === 1 << 1) {
            // 在右侧
            let width = e.clientX - startX + startDialogWidth;
            if (width < minWidth) {
              width = minWidth;
            } else if (width > maxWidth) {
              width = maxWidth;
            }
            // this.elDialog.style.cssText += `;width:${width}px`;
            this.width = `${width}px`;
          }
          if ((this.resizeType & (1 << 2)) === 1 << 2) {
            // 在上侧
            let top = e.clientY - startY + startDialogOffsetTop;
            // 边缘处理
            if (top < 0) {
              top = 0;
            }
            let height = elDialogRect.bottom - top;
            if (height < minHeight) {
              height = minHeight;
              top = elDialogRect.bottom - height;
            }
            // this.elDialog.style.cssText += `;top:${top}px;height:${height}px`;
            this.elDialog.style.cssText += `;top:${top}px`;
            this.height = `${height}px`;
          } else if ((this.resizeType & (1 << 3)) === 1 << 3) {
            // 在下侧
            let height = e.clientY - startY + startDialogHeight;
            if (height < minHeight) {
              height = minHeight;
            } else if (height > maxHeight) {
              height = maxHeight;
            }
            // this.elDialog.style.cssText += `;height:${height}px`;
            this.height = `${height}px`;
          }
        };
        const onMouseUp = () => {
          this.isResizing = false;
          // this.elDialogWrap.style.cssText += ";cursor:default";
          window.removeEventListener("mousemove", onMouseMove);
          window.removeEventListener("mouseup", onMouseUp);
        };

        window.addEventListener("mousemove", onMouseMove);
        window.addEventListener("mouseup", onMouseUp);
      }
    }
    onDialogWrapMouseMove(e) {
      // 非全屏和非移动状态时候生效
      if (!this.isFullScreen && !this.isMoving && !this.isResizing) {
        const offset = 7;
        // const elDialogRect = this.elDialog.getBoundingClientRect();
        const left = this.elDialog.offsetLeft;
        const right = this.elDialog.offsetLeft + this.elDialog.offsetWidth;
        const top = this.elDialog.offsetTop;
        const bottom = this.elDialog.offsetTop + this.elDialog.offsetHeight;
        // 首先必须保证光标是在区域内
        if (left < e.clientX && e.clientX < right && top < e.clientY && e.clientY < bottom) {
          const isOnLeft = left < e.clientX && e.clientX < left + offset;
          const isOnRight = right - offset < e.clientX && e.clientX < right;
          const isOnTop = top < e.clientY && e.clientY < top + offset;
          const isOnBottom = bottom - offset < e.clientY && e.clientY < bottom;
          // 鼠标按下，计算当前元素距离可视区的距离
          if (isOnLeft && isOnTop) {
            this.resizeType = (1 << 0) ^ (1 << 2);
            this.elDialogWrap.style.cssText += ";cursor:nw-resize";
          } else if (isOnLeft && isOnBottom) {
            this.resizeType = (1 << 0) ^ (1 << 3);
            this.elDialogWrap.style.cssText += ";cursor:ne-resize";
          } else if (isOnRight && isOnTop) {
            this.resizeType = (1 << 1) ^ (1 << 2);
            this.elDialogWrap.style.cssText += ";cursor:ne-resize";
          } else if (isOnRight && isOnBottom) {
            this.resizeType = (1 << 1) ^ (1 << 3);
            this.elDialogWrap.style.cssText += ";cursor:nw-resize";
          } else if (isOnLeft) {
            this.resizeType = 1 << 0;
            this.elDialogWrap.style.cssText += ";cursor:e-resize";
          } else if (isOnRight) {
            this.resizeType = 1 << 1;
            this.elDialogWrap.style.cssText += ";cursor:e-resize";
          } else if (isOnTop) {
            this.resizeType = 1 << 2;
            this.elDialogWrap.style.cssText += ";cursor:n-resize";
          } else if (isOnBottom) {
            this.resizeType = 1 << 3;
            this.elDialogWrap.style.cssText += ";cursor:n-resize";
          } else {
            this.resizeType = 0;
            this.elDialogWrap.style.cssText += ";cursor:default";
          }
        } else {
          this.resizeType = 0;
          this.elDialogWrap.style.cssText += ";cursor:default";
        }
      }
    }
    onMouseDown(e) {
      // 只有非全屏化的时候使用才有意义
      if (!this.isFullScreen) {
        this.isMoving = true;
        const elDialogRect = this.elDialog.getBoundingClientRect();
        // 鼠标按下，计算当前元素距离可视区的距离
        const disX = e.clientX - this.elDialogHeader.offsetLeft;
        const disY = e.clientY - this.elDialogHeader.offsetTop;

        const dragDomWidth = this.elDialog.offsetWidth;
        const dragDomHeight = this.elDialog.offsetHeight;

        const screenWidth = document.body.clientWidth;
        const screenHeight = document.body.clientHeight;

        const minDragDomLeft = this.elDialog.offsetLeft;
        const maxDragDomLeft = screenWidth - this.elDialog.offsetLeft - dragDomWidth;

        const minDragDomTop = this.elDialog.offsetTop;
        const maxDragDomTop = screenHeight - this.elDialog.offsetTop - dragDomHeight;
        // 获取到的值带px 正则匹配替换
        // const styL = getStyle(elDialog, "left");
        // const styT = getStyle(elDialog, "top");
        const onMouseMove = e => {
          // 通过事件委托，计算移动的距离
          let left = e.clientX - disX;
          let top = e.clientY - disY;

          // 边界处理
          if (-left > minDragDomLeft) {
            left = -minDragDomLeft;
          } else if (left > maxDragDomLeft) {
            left = maxDragDomLeft;
          }

          if (-top > minDragDomTop) {
            top = -minDragDomTop;
          } else if (top > maxDragDomTop) {
            top = maxDragDomTop;
          }

          // 移动当前元素
          this.elDialog.style.cssText += `;left:${left + elDialogRect.x}px;top:${top + elDialogRect.y}px`;
        };

        const onMouseUp = () => {
          this.isMoving = false;
          window.removeEventListener("mousemove", onMouseMove);
          window.removeEventListener("mouseup", onMouseUp);
        };

        window.addEventListener("mousemove", onMouseMove);
        window.addEventListener("mouseup", onMouseUp);
      }
    }

    onDialogOpen() {
      // body 会延时加载，所以窗口打开的时候设置才有效
      this.elDialogBody.classList.add("flex-1", "position-relative", "p-0");

      //! 这里顺序不能改变，否则 getBoundingClientRect 结果不对
      const elDialogRect = this.elDialog.getBoundingClientRect();
      // 修正样式和位置
      this.elDialog.style.cssText += `;top:${(window.innerHeight - elDialogRect.height) / 2}px;left:${(window.innerWidth - elDialogRect.width) / 2}px`; // 默认位置

      // 样式都设置完毕了，这里进行标记
      this.isStyleReady = true;

      this.elDialogHeader.addEventListener("mousedown", this.onMouseDown);
    }

    beforeClose = done => {
      done();
    };

    onDialogClosed() {}
  }
</script>

<style lang="scss" scoped>
  .ju-dialog {
    overflow: hidden;

    :deep {
      .el-dialog {
        // 代码中还一个宽度跟这个值一致
        border: 7px solid rgba(0, 0, 0, 0.3);
        border-radius: 6px;
        background-clip: content;
        -webkit-background-clip: content; // 使得边框的透明度能够生效
        transition: all 0.2s; // 动画会影响表格拖动
        max-height: 100%;
        max-width: 100%;
      }
      .el-dialog__header {
        border-bottom: 1px solid var(--theme-gray-200);
      }
      .el-dialog__body {
        padding: 0;
        overflow: hidden;
        font-size: 0;
      }
    }
    &.moving {
      :deep(.el-dialog) {
        transition: none; //
      }
    }
    &.fullscreen {
      :deep(.el-dialog) {
        top: 0 !important;
        left: 0 !important;
        right: 0 !important;
        bottom: 0 !important;
        width: auto !important;
        height: auto !important;
      }
    }
  }

  .toolbar {
    .ju-icon {
      font-size: 18px;
      cursor: pointer;
      transition: all 0.2s;

      &:hover {
        color: red;
        // transform: rotate(180deg);
      }

      &.ju-icon-close:hover {
        transform: rotate(180deg);
      }
    }
  }
  // 防止移动窗口时被iframe 捕获导致拖动出现问题
  .move-mask {
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    background-color: rgba(255, 255, 255, 0.00001);
  }
</style>
